// utility widgets
#include <wx/wx.h>
#include "wx/wxmisc.h"

wxFarRadio::wxFarRadio()
	: wxCheckBox()
{
	Next = this;
}

wxFarRadio::~wxFarRadio()
{
	BreakGroup();
}

void wxFarRadio::SetValue(bool val)
{
	wxCheckBox::SetValue(val);
	UpdatedValue();
}

void wxFarRadio::SetGroup(class wxFarRadio* grp)
{
	if (grp == this)
		return;

	wxFarRadio* checked = GetValue() ? this : NULL;

	for (wxFarRadio* gp = Next; gp != this; gp = gp->Next)
	{
		if (gp = grp)
			return;

		if (gp->GetValue())
			checked = gp;
	}

	wxFarRadio* link = Next;
	Next = grp;
	bool clear_checked = false;
	wxFarRadio* gp;

	for (gp = grp; gp->Next != grp; gp = gp->Next)
	{
		if (checked && GetValue())
			clear_checked = true;
	}

	gp->Next = link;

	if (checked && gp->GetValue())
		clear_checked = true;

	if (clear_checked)
		checked->SetValue(false);

	int l;

	for (l = 1, gp = Next; gp != this; gp = gp->Next, l++);
}

void wxFarRadio::BreakGroup()
{
	wxFarRadio** gp;

	for (gp = &Next; *gp != this; gp = &(*gp)->Next);

	*gp = Next;
	Next = this;
}

wxFarRadio* wxFarRadio::GetNext()
{
	return Next;
}

void wxFarRadio::UpdatedValue()
{
	if (!GetValue())
	{
		wxFarRadio* gp;

		// just like system wx, ensure at least one always checked
		for (gp = Next; gp != this; gp = gp->Next)
			if (gp->GetValue())
				break;

		if (gp == this)
		{
			SetValue(true);
			return;
		}
	}
	else
		for (wxFarRadio* gp = Next; gp != this; gp = gp->Next)
			gp->SetValue(false);
}

void wxFarRadio::UpdateEvt(wxCommandEvent &ev)
{
	UpdatedValue();
	ev.Skip();
}

IMPLEMENT_DYNAMIC_CLASS(wxFarRadio, wxCheckBox);
BEGIN_EVENT_TABLE(wxFarRadio, wxCheckBox)
	EVT_CHECKBOX(wxID_ANY, wxFarRadio::UpdateEvt)
END_EVENT_TABLE()

bool wxBoolIntValidator::TransferToWindow()
{
	if (!vptr)
		return false;

	bool checked = (*vptr & mask) == val;
	wxCheckBox* cb = wxDynamicCast(GetWindow(), wxCheckBox);

	if (cb)
	{
		cb->SetValue(checked);
		return true;
	}

	wxRadioButton* rb = wxDynamicCast(GetWindow(), wxRadioButton);

	if (rb)
	{
		rb->SetValue(checked);
		return true;
	}

	return false;
}

bool wxBoolIntValidator::TransferFromWindow()
{
	if (!vptr)
		return false;

	bool nv = false;
	wxCheckBox* cb = wxDynamicCast(GetWindow(), wxCheckBox);

	if (cb)
		nv = cb->GetValue();
	else
	{
		wxRadioButton* rb = wxDynamicCast(GetWindow(), wxRadioButton);

		if (rb)
			nv = rb->GetValue();
		else
			return false;
	}

	if (mask == ~0 && !nv && *vptr != val)
		return true;

	*vptr = (*vptr & ~mask) | (nv ? val : 0);
	return true;
}

bool wxBoolRevValidator::TransferToWindow()
{
	if (!vptr)
		return false;

	wxCheckBox* cb = wxDynamicCast(GetWindow(), wxCheckBox);

	if (cb)
	{
		cb->SetValue(!*vptr);
		return true;
	}

	wxRadioButton* rb = wxDynamicCast(GetWindow(), wxRadioButton);

	if (rb)
	{
		rb->SetValue(!*vptr);
		return true;
	}

	return false;
}

bool wxBoolRevValidator::TransferFromWindow()
{
	if (!vptr)
		return false;

	wxCheckBox* cb = wxDynamicCast(GetWindow(), wxCheckBox);

	if (cb)
		*vptr = !cb->GetValue();
	else
	{
		wxRadioButton* rb = wxDynamicCast(GetWindow(), wxRadioButton);

		if (rb)
			*vptr = !rb->GetValue();
		else
			return false;
	}

	return true;
}

#include <wx/filepicker.h>

bool wxFileDirPickerValidator::TransferToWindow()
{
	if (!vptr)
		return false;

	wxFilePickerCtrl* fp = wxDynamicCast(GetWindow(), wxFilePickerCtrl);

	if (fp)
	{
		fp->SetPath(*vptr);
		return true;
	}

	wxDirPickerCtrl* dp = wxDynamicCast(GetWindow(), wxDirPickerCtrl);

	if (dp)
	{
		dp->SetPath(*vptr);
		return true;
	}

	return false;
}

bool wxFileDirPickerValidator::TransferFromWindow()
{
	if (!vptr)
		return false;

	wxFilePickerCtrl* fp = wxDynamicCast(GetWindow(), wxFilePickerCtrl);

	if (fp)
	{
		*vptr = fp->GetPath();
		return true;
	}

	wxDirPickerCtrl* dp = wxDynamicCast(GetWindow(), wxDirPickerCtrl);

	if (dp)
	{
		*vptr = dp->GetPath();
		return true;
	}

	return false;
}

#include <wx/clrpicker.h>

bool wxColorValidator::TransferToWindow()
{
	if (!ptr32 && !ptr16)
		return false;

	wxColourPickerCtrl* cp = wxDynamicCast(GetWindow(), wxColourPickerCtrl);

	if (!cp)
		return false;

	if (ptr32)
		cp->SetColour(wxColor(((*ptr32 >> 16) & 0xff),
		                      ((*ptr32 >> 8) & 0xff),
		                      ((*ptr32) & 0xff)));
	else
		cp->SetColour(wxColor(((*ptr16 << 3) & 0xf8),
		                      ((*ptr16 >> 2) & 0xf8),
		                      ((*ptr16 >> 7) & 0xf8)));

	return true;
}

bool wxColorValidator::TransferFromWindow()
{
	if (!ptr32 && !ptr16)
		return false;

	wxColourPickerCtrl* cp = wxDynamicCast(GetWindow(), wxColourPickerCtrl);

	if (!cp)
		return false;

	wxColor c = cp->GetColour();

	if (ptr32)
		*ptr32 = ((c.Red() & 0xff) << 16) +
		         ((c.Green() & 0xff) << 8) +
		         ((c.Blue() & 0xff));
	else
		*ptr16 = ((c.Red() & 0xf8) >> 3) +
		         ((c.Green() & 0xf8) << 2) +
		         ((c.Blue() & 0xf8) << 7);

	return true;
}

static void enable(wxWindow_v controls, std::vector<int>reverse, bool en)
{
	for (int i = 0; i < controls.size(); i++)
		controls[i]->Enable(reverse.size() <= i || !reverse[i] ? en : !en);
}

#define boolen(r) do { \
    int en; \
    wxCheckBox *cb = wxDynamicCast(GetWindow(), wxCheckBox); \
    if(cb) \
    en = cb->GetValue(); \
    else { \
    wxRadioButton *rb = wxDynamicCast(GetWindow(), wxRadioButton); \
    if(!rb) \
        return false; \
    en = rb->GetValue(); \
    } \
    enable(controls, reverse, r ? !en : en); \
    return true; \
} while(0)

bool wxBoolEnValidator::TransferToWindow()
{
	if (!wxGenericValidator::TransferToWindow())
		return false;

	boolen(false);
}

bool wxBoolIntEnValidator::TransferToWindow()
{
	if (!wxBoolIntValidator::TransferToWindow())
		return false;

	boolen(false);
}

bool wxBoolRevEnValidator::TransferToWindow()
{
	if (!wxBoolRevValidator::TransferToWindow())
		return false;

	boolen(true);
}

void wxBoolEnHandler::ToggleCheck(wxCommandEvent &ev)
{
	enable(controls, reverse, ev.IsChecked());
	ev.Skip();
}

void wxBoolEnHandler::Enable(wxCommandEvent &ev)
{
	enable(controls, reverse, true);
	ev.Skip();
}

void wxBoolEnHandler::Disable(wxCommandEvent &ev)
{
	enable(controls, reverse, false);
	ev.Skip();
}

static const wxChar* /* const */ val_hexdigits_s[] =
{
	wxT("0"), wxT("1"), wxT("2"), wxT("3"), wxT("4"), wxT("5"), wxT("6"),
	wxT("7"), wxT("8"), wxT("9"), wxT("A"), wxT("B"), wxT("C"), wxT("D"),
	wxT("E"), wxT("F"), wxT("a"), wxT("b"), wxT("c"), wxT("d"), wxT("e"),
	wxT("f")
};

const wxArrayString val_hexdigits(sizeof(val_hexdigits_s) / sizeof(val_hexdigits_s[0]),
                                  val_hexdigits_s);

static const wxChar* /* const */ val_sigdigits_s[] =
{
	wxT("0"), wxT("1"), wxT("2"), wxT("3"), wxT("4"), wxT("5"), wxT("6"),
	wxT("7"), wxT("8"), wxT("9"), wxT("-"), wxT("+")
};

const wxArrayString val_sigdigits(sizeof(val_sigdigits_s) / sizeof(val_sigdigits_s[0]),
                                  val_sigdigits_s);

static const wxChar* /* const */ val_unsdigits_s[] =
{
	wxT("0"), wxT("1"), wxT("2"), wxT("3"), wxT("4"), wxT("5"), wxT("6"),
	wxT("7"), wxT("8"), wxT("9")
};

const wxArrayString val_unsdigits(sizeof(val_unsdigits_s) / sizeof(val_unsdigits_s[0]),
                                  val_unsdigits_s);
